﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;
using System.Data;

namespace l1cs.server.datatables
{
    // http://d.hatena.ne.jp/hilapon/20100708/1278588192
    // よりソースコードを拝借して少し改変
    class MySqlWrapper : IDisposable
    {
        private static Logger _log = Logger.getLogger( typeof( MySqlWrapper ).FullName );
        /// <summary>
        /// コネクション文字列
        /// </summary>
        private static String _connstr;
        /// <summary>コネクション</summary>
        MySqlConnection _connection;
        /// <summary>トランザクション</summary>
        MySqlTransaction _transaction;
        bool _disposed;

        public MySqlWrapper()
        {
            _connection = new MySqlConnection( _connstr );
            Open();
        }

        public MySqlConnection getConnection()
        {
            return _connection;
        }
        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="connectString">接続文字列</param>
        public MySqlWrapper( string connectString )
        {
            _connection = new MySqlConnection( connectString );
            Open();
        }

        public static void setDatabaseSettings( String host, String dbname, String user, String password )
        {
            _connstr = string.Format(
                "userid={0};password={1};database={2};Host={3};Character Set=sjis",
                user, password, dbname, host );
        }

        /// <summary>
        /// リソースを解放します。
        /// </summary>
        /// <param name="disposing"></param>
        protected void Dispose( bool disposing )
        {

            if ( _disposed == false )
            {
                if ( disposing )
                {
                    //
                    if ( _transaction != null )
                    {
                        _transaction.Dispose();
                    }

                    if ( _connection != null )
                    {
                        this.Close();
                        _connection.Dispose();
                    }
                }
                _disposed = true;
            }
        }

        /// <summary>
        /// リソースを解放します。
        /// </summary>
        public void Dispose()
        {
            this.Dispose( true );
            GC.SuppressFinalize( this );
        }

        /// <summary>
        /// トランザクションを開始します。
        /// </summary>
        public MySqlTransaction BeginTransaction()
        {

            try
            {
                _transaction = _connection.BeginTransaction( IsolationLevel.RepeatableRead );
            }
            catch ( Exception e )
            {
                _log.info( e.Message + "\n" + e.StackTrace );
                throw;
            }
            return _transaction;
        }

        /// <summary>
        /// トランザクションを開始します。
        /// </summary>
        public MySqlTransaction BeginTransaction( IsolationLevel isolationLevel )
        {

            try
            {
                _transaction = _connection.BeginTransaction( isolationLevel );
            }
            catch ( Exception e )
            {
                _log.info( e.Message + "\n" + e.StackTrace );
                throw;
            }
            return _transaction;
        }

        /// <summary>
        /// データベースへの接続を閉じます。
        /// </summary>
        public void Close()
        {
            try
            {
                if ( _connection != null &&
                    _connection.State == ConnectionState.Open )
                {
                    _connection.Close();
                }
            }
            catch ( Exception e )
            {
                _log.info( e.Message + "\n" + e.StackTrace );
                throw;
            }
        }

        /// <summary>
        /// トランザクション処理をコミットします。
        /// </summary>
        public void Commit()
        {
            try
            {
                if ( _transaction != null )
                {
                    _transaction.Commit();
                }
            }
            catch ( Exception e )
            {
                _log.info( e.Message + "\n" + e.StackTrace );
                throw;
            }
        }

        /// <summary>
        /// 接続に対して SQL ステートメントを実行し、影響を受けた行数を返します。 
        /// </summary>
        /// <param name="command"><see cref="MySqlCommand">MySqlCommand</see> オブジェクト</param>
        /// <returns>影響を受けた行数</returns>
        public int ExecNonQuery( MySqlCommand command )
        {

            int ret = 0;
            try
            {
                command.Connection = _connection;
                if ( _transaction != null )
                {
                    command.Transaction = _transaction;
                }
                ret = command.ExecuteNonQuery();
            }
            catch ( Exception e )
            {
                _log.info( e.Message + "\n" + e.StackTrace );
                throw;
            }
            return ret;
        }

        /// <summary>
        /// クエリを実行し、そのクエリが返す結果セットの最初の行にある最初の列を返します。
        /// </summary>
        /// <param name="sqlstr"><see cref="String">String</see> SQL文</param>
        /// <returns>結果セットの最初の行の最初の列</returns>
        public Object ExecScaler( String sqlstr )
        {
            MySqlCommand command = new MySqlCommand( sqlstr );
            return ExecScaler( command );
        }

        /// <summary>
        /// クエリを実行し、そのクエリが返す結果セットの最初の行にある最初の列を返します。
        /// </summary>
        /// <param name="command"><see cref="MySqlCommand">MySqlCommand</see> オブジェクト</param>
        /// <returns>結果セットの最初の行の最初の列</returns>
        public Object ExecScaler( MySqlCommand command )
        {

            Object ret = null;
            command.Connection = _connection;
            try
            {
                if ( _transaction != null )
                {
                    command.Transaction = _transaction;
                }
                ret = command.ExecuteScalar();
            }
            catch ( Exception e )
            {
                _log.info( e.Message + "\n" + e.StackTrace );
                throw;
            }
            return ret;
        }

        /// <summary>
        /// データテーブル取得処理
        /// </summary>
        /// <param name="sqlstr"><see cref="String">String</see> SQL文</param>
        /// <returns><see cref="DataTable">DataTable</see>オブジェクト</returns>
        /// <remarks>
        /// パラメータに渡されたコマンドを実行し、データテーブルを取得します。
        /// </remarks>
        public DataTable GetDataTable( String sqlstr )
        {
            MySqlCommand command = new MySqlCommand( sqlstr );
            return GetDataTable( command );
        }

        /// <summary>
        /// データテーブル取得処理
        /// </summary>
        /// <param name="command"><see cref="MySqlCommand">MySqlCommand</see> オブジェクト</param>
        /// <returns><see cref="DataTable">DataTable</see>オブジェクト</returns>
        /// <remarks>
        /// パラメータに渡されたコマンドを実行し、データテーブルを取得します。
        /// </remarks>
        public DataTable GetDataTable( MySqlCommand command )
        {

            DataTable ret = null;
            try
            {
                command.Connection = _connection;
                if ( _transaction != null )
                {
                    command.Transaction = _transaction;
                }
                MySqlDataAdapter adapter = new MySqlDataAdapter( command );
                MySqlCommandBuilder builder = new MySqlCommandBuilder( adapter );
                ret = new DataTable();
                adapter.Fill( ret );

            }
            catch ( Exception e )
            {
                _log.info( e.Message + "\n" + e.StackTrace );
                ret = null;
                throw;
            }
            return ret;
        }

        /// <summary>
        /// データベース接続を開きます。 
        /// </summary>
        public void Open()
        {
            try
            {
                if ( _connection != null &&
                    _connection.State != ConnectionState.Open )
                {
                    _connection.Open();
                }
            }
            catch ( Exception e )
            {
                _log.info( e.Message + "\n" + e.StackTrace );
                throw;
            }
        }

        /// <summary>
        /// トランザクション処理をロールバックします。
        /// </summary>
        public void Rollback()
        {

            try
            {
                if ( _transaction != null )
                {
                    _transaction.Rollback();
                }
            }
            catch ( Exception e )
            {
                _log.info( e.Message + "\n" + e.StackTrace );
                throw;
            }
        }

        /// <summary>
        /// データテーブル更新処理
        /// </summary>
        /// <param name="source">更新対象となるデータテーブル</param>
        /// <param name="command"><see cref="MySqlCommand">MySqlCommand</see> オブジェクト</param>
        /// <returns>更新に成功した行数</returns>
        public int Update( DataTable source, MySqlCommand command )
        {

            int ret = 0;
            try
            {
                command.Connection = _connection;
                if ( _transaction != null )
                {
                    command.Transaction = _transaction;
                }
                MySqlDataAdapter adapter = new MySqlDataAdapter( command );
                MySqlCommandBuilder builder = new MySqlCommandBuilder( adapter );
                ret = adapter.Update( source );

            }
            catch ( Exception e )
            {
                _log.info( e.Message + "\n" + e.StackTrace );
                throw;
            }
            return ret;
        }
    }
}
